package avicit.bdp.dgs.qa.service.algo.raw.data.pcm;

import avicit.bdp.common.dto.StorageResourceConf;
import avicit.bdp.common.utils.uploads.FileAdapterUtils;
import avicit.bdp.dgs.qa.dao.QaDataSourceDAO;
import avicit.bdp.dgs.qa.dto.FtdpFileDTO;
import avicit.bdp.dgs.qa.dto.JobDTO;
import avicit.bdp.dgs.qa.dto.RuleDTO;
import avicit.bdp.dgs.qa.service.algo.IAlgo;
import avicit.bdp.dgs.qa.service.algo.raw.data.pcm.checker.PCMFileChecker;
import avicit.bdp.dgs.qa.utils.constant.QaConstant;
import avicit.bdp.ftdp.api.FtdpResourceApi;
import avicit.platform6.core.exception.BusinessException;
import avicit.platform6.core.rest.msg.ResponseMsg;
import com.alibaba.fastjson2.JSONObject;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.eclipse.jetty.http.HttpStatus;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @金航数码科技有限责任公司
 * @作者：developer
 * @邮箱：developer@avic-digital.com
 * @创建时间： 2023-10-27
 * @类说明：PcmFileAlog
 * @修改记录：
 * @注意事项：
 * @主要功能：PCM文件校验算法
 */
@Component("pcm")
public class PcmFileAlog implements IAlgo {
    private static final Logger logger = LoggerFactory.getLogger(PcmFileAlog.class);

    /**
     * .inf文件后缀
     */
    public static final String INF_FILE_SUFFIX = ".inf";

    /**
     * pcm文件和inf文件存储位置
     */
    public static final String INPUT_TYPE = "minio";

    @Autowired
    private QaDataSourceDAO qaDataSourceDAO;

    @Autowired
    private FtdpResourceApi ftdpResourceApi;

    /**
     * 执行算法
     *
     * @param jobDTO   任务信息
     * @param ruleList 规则信息
     * @return 执行结果
     */
    @Override
    public ResponseMsg<List<FtdpFileDTO>> execute(JobDTO jobDTO, List<RuleDTO> ruleList) {
        List<FtdpFileDTO> pcmFileList = null;
        ResponseMsg<List<FtdpFileDTO>> responseMsg = new ResponseMsg<>();

        try {
            // 合法性检查
            validate(jobDTO, ruleList);

            // 获取pcm文件列表和inf文件
            List<FtdpFileDTO> fileList = getFileList(jobDTO.getResourceIds());
//            List<FtdpFileDTO> fileList = mockFileList();

            // 获取inf文件
            FtdpFileDTO infFile = getInfFile(fileList, jobDTO.getOffsiteDataId());

            // 获取pcm文件
            pcmFileList = getPcmFileList(fileList);

            // 遍历文件，执行pcm校验
            executeInner(jobDTO, ruleList, infFile, pcmFileList);
        } catch (Exception e) {
            setResponse(responseMsg, HttpStatus.INTERNAL_SERVER_ERROR_500, e.getMessage(), pcmFileList);
            return responseMsg;
        }

        setResponse(responseMsg, HttpStatus.OK_200, null, pcmFileList);

        return responseMsg;
    }

    /**
     * 遍历文件列表，执行pcm文件校验
     *
     * @param jobDTO
     * @param ruleList
     * @param infFile
     * @param pcmFileList
     */
    private void executeInner(JobDTO jobDTO, List<RuleDTO> ruleList, FtdpFileDTO infFile, List<FtdpFileDTO> pcmFileList) {
        if (CollectionUtils.isEmpty(ruleList)) {
            logger.warn(String.format("质量任务[%s]中pcm文件列表为空", jobDTO.getName()));
            return;
        }

        List<String> errMsgList = new ArrayList<>();
        for (FtdpFileDTO pcmFile : pcmFileList) {
            String fileName = pcmFile.getName();
            if (StringUtils.isEmpty(fileName)) {
                logger.error("未配置文件名称，校验失败");
                errMsgList.add("未配置文件名称，校验失败");
                continue;
            }

            // 调用PCM算法接口，执行校验
            PCMFileChecker.check(buildPcmParaMap(infFile, pcmFile));
        }

        if (CollectionUtils.isNotEmpty(errMsgList)) {
            throw new BusinessException(JSONObject.toJSONString(errMsgList));
        }
    }

    /**
     * 合法性检查
     *
     * @param jobDTO
     * @param ruleList
     * @return
     */
    private void validate(JobDTO jobDTO, List<RuleDTO> ruleList) {
        if (jobDTO == null) {
            logger.error("作业为null");
            throw new BusinessException("作业为null，文件校验失败");
        }
        if (CollectionUtils.isEmpty(ruleList)) {
            // 未能自动匹配到模板，表明当前文件的数据格式不是PCM
            logger.error("当前仅支持PCM格式的文件");
            throw new BusinessException("当前仅支持PCM格式的文件，校验失败");
        }
    }

    /**
     * 获取待校验文件列表
     *
     * @param resourceIds
     * @return
     */
    private List<FtdpFileDTO> getFileList(String resourceIds) {
        if (StringUtils.isEmpty(resourceIds)) {
            return new ArrayList<>();
        }

        List<FtdpFileDTO> fileList = this.qaDataSourceDAO.getFileList(null, Arrays.asList(resourceIds.trim().split(QaConstant.COMMA)));
        if (CollectionUtils.isEmpty(fileList)) {
            return new ArrayList<>();
        }

        return fileList;
    }

    /**
     * 获取inf文件
     *
     * @param fileList
     * @param ftdpOffsiteDataId
     * @return
     */
    private FtdpFileDTO getInfFile(List<FtdpFileDTO> fileList, String ftdpOffsiteDataId) {
        FtdpFileDTO infFile = new FtdpFileDTO();

        infFile.setFullName(getInfFilePath(ftdpOffsiteDataId));

        return infFile;
    }

    /**
     * 获取inf文件全路径名称
     *
     * @param ftdpOffsiteDataId
     * @return
     */
    private String getInfFilePath(String ftdpOffsiteDataId) {
        if (StringUtils.isEmpty(ftdpOffsiteDataId)) {
            logger.error("试飞信息ID为空.");
            return null;
        }

        String infFileFullName = this.ftdpResourceApi.getInfPathById(ftdpOffsiteDataId);
        if (StringUtils.isEmpty(infFileFullName)) {
            logger.error("获取inf文件失败,试飞信息ID:{}.", ftdpOffsiteDataId);
            return null;
        }

        return infFileFullName;
    }

    /**
     * 获取pcm文件列表
     *
     * @param fileList
     * @return
     */
    private List<FtdpFileDTO> getPcmFileList(List<FtdpFileDTO> fileList) {
        if (CollectionUtils.isEmpty(fileList)) {
            return fileList;
        }

        return fileList.stream().filter(item -> !(item.getName().endsWith(INF_FILE_SUFFIX))).collect(Collectors.toList());
    }

    /**
     * 构建pcm算法参数列表
     *
     * @param infFile
     * @param pcmFile
     * @return
     */
    private Map<String, Object> buildPcmParaMap(FtdpFileDTO infFile, FtdpFileDTO pcmFile) {
        Map<String, Object> paraMap = new HashMap<>();
        Map<String, Object> inputMap = new HashMap<>();

        // 获取minio连接信息
        StorageResourceConf conf = FileAdapterUtils.getStorageResourceByProjectId(null);
        String endPoint = conf.getEndPoint();
        String accessKey = conf.getAccessKey();
        String secretKey = conf.getSecretKey();
        String bucket = conf.getStoragePath();
//        String endPoint = "http://10.216.92.71:9000";
//        String accessKey = "minioadmin";
//        String secretKey = "minioadmin";
//        String bucket = "test";

        inputMap.put("inputType", INPUT_TYPE);
        inputMap.put("icdFilePath", infFile.getFullName());
        inputMap.put("inputFilePath", pcmFile.getFullName());
        inputMap.put("groupParams", null);
        inputMap.put("icdFileStartTime", null);
        inputMap.put("icdFileEndTime", null);
        inputMap.put("endPoint", endPoint);
        inputMap.put("accessKey", accessKey);
        inputMap.put("secretKey", secretKey);
        inputMap.put("bucketName", bucket);

        paraMap.put("inputParams", inputMap);
        paraMap.put("outputParams", inputMap);

        return paraMap;
    }

    /**
     * 设置返回消息
     *
     * @param responseMsg
     * @param retCode
     * @param errMsg
     * @param fileList
     */
    private void setResponse(ResponseMsg<List<FtdpFileDTO>> responseMsg, Integer retCode, String errMsg, List<FtdpFileDTO> fileList) {
        if (responseMsg.getResponseBody() == null) {
            responseMsg.setResponseBody(new ArrayList<>());
        }
        if (StringUtils.isNotEmpty(errMsg)) {
            responseMsg.setErrorDesc(errMsg);
        }
        if (CollectionUtils.isNotEmpty(fileList)) {
            responseMsg.setResponseBody(fileList);
        }

        responseMsg.setRetCode(Integer.toString(retCode));
    }

    /************************************* UT单元测试 *************************************/
    /**
     * 模拟文件列表
     *
     * @return
     */
    private List<FtdpFileDTO> mockFileList() {
        String fileJsonString1 = "{\n" +
                "\t\"directory\": 5282794,\n" +
                "\t\"fullName\": \"991.inf\",\n" +
                "\t\"name\": \"991.inf\",\n" +
                "\t\"pid\": \"8a58bcf68b45edaa018b6b2693141df1\",\n" +
                "\t\"size\": 36,\n" +
                "\t\"type\": 0\n" +
                "}";
        String fileJsonString2 = "{\n" +
                "\t\"directory\": 0,\n" +
                "\t\"fullName\": \"991.DCM\",\n" +
                "\t\"name\": \"991.DCM\",\n" +
                "\t\"pid\": \"8a58bcf68b45edaa018b6b2693141df2\",\n" +
                "\t\"size\": 356622152,\n" +
                "\t\"type\": 0\n" +
                "}";

        List<FtdpFileDTO> fileList = new ArrayList<>();
        fileList.add(JSONObject.parseObject(fileJsonString1, FtdpFileDTO.class));
        fileList.add(JSONObject.parseObject(fileJsonString2, FtdpFileDTO.class));

        return fileList;
    }
}
